﻿using System;
using System.Collections.Generic;
using System.Reflection;
using System.Linq;
using System.Text;
using System.Web.UI.WebControls;
using Vici.Mvc.Source;
using Vici.Mvc.Source.Common;

namespace Vici.Mvc
{
    #region 枚举条件
    public enum Validation
    {
        email,
        /// <summary>
        /// 必填字段
        /// </summary>
        required,
        url,
        date,
        /// <summary>
        /// 合法的数字,包括小数,负数
        /// </summary>
        number,
        /// <summary>
        /// 整数
        /// </summary>
        digits,
        equalTo
    }
    #endregion
    [Serializable]
    public class MyForm
    {
        #region 属性
        private SerializableDictionary<string, MyField> _fields = new SerializableDictionary<string, MyField>();
        private View _view;
        private SerializableDictionary<string, string> _errors = null;
        public string[][] Errors
        {
            get
            {
                if (_errors != null)
                {
                    string[][] errors = new string[_errors.Count][];
                    int i = 0;
                    foreach (KeyValuePair<string, string> keys in _errors)
                    {
                        errors[i] = new string[2];
                        errors[i][0] = keys.Key;
                        errors[i][1] = keys.Value;
                        i++;
                    }
                    return errors;
                }
                return null;
            }
        }
        public MyField this[string name]
        {
            get
            {
                if (!_fields.ContainsKey(name))
                {
                    _fields.Add(name, new MyField(name, _view));
                }
                return _fields[name];
            }
            set
            {
                this[name] = value;
            }
        }
        public SerializableDictionary<string, MyField> MyFields
        {
            get
            {
                return _fields;
            }
            set
            {
                _fields = value;
            }
        }
        #endregion
        #region 构造函数
        public MyForm(View view)
        {
            _view = view;
            _view.RegisterJavascriptInclude("validate", true, "/Content/Scripts/jquery.validate.min.js");
            _view.RegisterJavascriptInclude("metadata", true, "/Content/Scripts/jquery.metadata.js");

        }
        public MyForm()
        {

        }
        #endregion
        #region 绑定方法
        public void Bind(object dataSource = null)
        {
            PropertyInfo[] pInfos = null;
            if (dataSource != null)
            {
                pInfos = dataSource.GetType().GetProperties();
            }
            foreach (KeyValuePair<string, MyField> keys in _fields)
            {
                if (pInfos != null)
                {
                    List<PropertyInfo> pInfo = pInfos.Where(a => a.Name == keys.Key).ToList();
                    _view.ViewData[keys.Key] = keys.Value.Render(pInfo.Count > 0 ? pInfo[0].GetValue(dataSource, null) : null);
                }
                else
                {
                    _view.ViewData[keys.Key] = keys.Value.Render();
                }
            }
            String formStr = XmlSerializer.SerializeToString<MyForm>(this);
          //  formStr = XP.Utilities.Utility.Security.Security.EncryptDES(formStr);
            _view.HTML = string.Format("<input type=\"hidden\" name=\"_MyForm_\" id=\"_MyForm_\" value=\"{0}\" />", formStr);
            _view.RegisterJavascriptInclude("jQueryForm", true, "/Content/Scripts/jquery.form.js");
        }
        /// <summary>
        /// 服务端验证方法,验证失败将输出XML信息
        /// </summary>
        /// <returns></returns>
        public bool Validate()
        {
            bool valid = true;
            foreach (KeyValuePair<string, MyField> keys in _fields)
            {
                if (!Check(keys.Value))
                {
                    if (_errors == null)
                    {
                        _errors = new SerializableDictionary<string, string>();
                    }
                    _errors.Add(keys.Key, keys.Value.Message);
                    valid = false;
                }
            }
            if (!valid) ShowError();
            return valid;
        }
        public void Save<T>(T t, string successText = "", bool end = true)
        {
            PropertyInfo[] sourcePInfos = t.GetType().GetProperties();
            foreach (PropertyInfo pInfo in sourcePInfos)
            {
                if (_fields.ContainsKey(pInfo.Name))
                {
                    MyField field = _fields[pInfo.Name];

                    if (!string.IsNullOrEmpty(field.SaveFolder) && string.IsNullOrEmpty(field.Value)) continue;
                    switch (pInfo.PropertyType.Name)
                    {
                        case "Int32":
                            pInfo.SetValue(t, int.Parse(_fields[pInfo.Name].Value), null);
                            break;
                        case "DateTime":
                            pInfo.SetValue(t, DateTime.Parse(_fields[pInfo.Name].Value), null);
                            break;
                        case "Boolean":
                            pInfo.SetValue(t, bool.Parse(_fields[pInfo.Name].Value), null);
                            break;
                        default:
                            pInfo.SetValue(t, _fields[pInfo.Name].Value, null);
                            break;
                    }
                }
            }
            MethodInfo method = t.GetType().GetMethod("Save");
            method.Invoke(t, null);
            if (end)
            {
                System.Web.HttpContext.Current.Response.Clear();
                System.Web.HttpContext.Current.Response.ContentType = "text/xml";
                System.Web.HttpContext.Current.Response.Write(string.Format("<result>{0}</result>", successText));
                System.Web.HttpContext.Current.Response.End();
            }
        }
        /// <summary>
        /// 验证指定的字段对象
        /// </summary>
        /// <param name="field"></param>
        /// <returns></returns>
        public bool Check(MyField field)
        {
            foreach (Validation validation in field.Validations)
            {
                switch (validation)
                {
                    case Validation.email:
                        System.Text.RegularExpressions.Regex reg = new System.Text.RegularExpressions.Regex(@"^[\w-]+(\.[\w-]+)*@[\w-]+(\.[\w-]+)+$");
                        if (!reg.IsMatch(field.Value))
                        {
                            field.Message = "请填写正确的EMAIL格式!";
                            return false;
                        }
                        break;
                    case Validation.required:
                        if (string.IsNullOrEmpty(field.Value))
                        {
                            field.Message = "该字段为必填项!";
                            return false;
                        }
                        break;
                    case Validation.digits:
                        decimal number;
                        bool isNumber = decimal.TryParse(field.Value, out number);
                        if (!isNumber)
                        {
                            field.Message = "该字段必须为数字!";
                            return false;
                        }
                        break;
                    case Validation.date:
                        DateTime date;
                        bool isDate = DateTime.TryParse(field.Value, out date);
                        if (!isDate)
                        {
                            field.Message = "请填写正确的日期格式!";
                            return false;
                        }
                        break;


                }
            }
            return true;
        }
        public void ShowError()
        {
            System.Web.HttpContext.Current.Response.Clear();
            System.Web.HttpContext.Current.Response.ContentType = "text/xml";
            StringBuilder sb = new StringBuilder();
            sb.Append("<Errors>");
            foreach (var item in this.Errors)
            {
                string field = item[0].ToString();
                string value = item[1].ToString();
                sb.Append(string.Format("<{0}>", field));
                sb.Append(value);
                sb.Append(string.Format("</{0}>", field));
            }
            sb.Append("</Errors>");
            System.Web.HttpContext.Current.Response.Write(sb.ToString());
            System.Web.HttpContext.Current.Response.End();
        }
        #endregion
        #region 静态方法
        public static MyForm GetRequest()
        {
            MyForm myForm = XmlSerializer.DeserializeFromString<MyForm>("XP.Utilities.Utility.Security.Security.DecryptDES(System.Web.HttpContext.Current.Request.Form[_MyForm_])");
            if (myForm != null)
            {
                System.Web.HttpRequest request = System.Web.HttpContext.Current.Request;
                int fileIndex = 1;
                foreach (KeyValuePair<string, MyField> keys in myForm.MyFields)
                {
                    System.Web.HttpPostedFile file = request.Files[keys.Key];
                    if (file == null)
                    {
                        if (keys.Value.Type == "Editor")
                        {
                            keys.Value.Value = keys.Value.Value = System.Web.HttpContext.Current.Request.Form[keys.Key + "_Editor"];
                        }
                        else
                        {
                            keys.Value.Value = System.Web.HttpContext.Current.Request.Form[keys.Key];
                        }
                    }
                    else
                    {
                        if (!string.IsNullOrEmpty(file.FileName))
                        {
                            string folder = myForm[keys.Key].SaveFolder;
                            if (!folder.StartsWith("/")) folder = "/" + folder;
                            string path = System.Web.HttpContext.Current.Server.MapPath(folder);
                            string fileName = "";//string.Format("{0}{1}{2}", XP.Utilities.Utility.WinHelper.GetFileName(), fileIndex, System.IO.Path.GetExtension(file.FileName));
                            file.SaveAs(string.Format("{0}\\{1}", path, fileName));
                            keys.Value.Value = string.Format("{0}/{1}", myForm[keys.Key].SaveFolder, fileName);
                            fileIndex++;
                        }
                    }
                }
            }
            return myForm;
        }
        #endregion
    }
    [Serializable]
    public class MyField
    {
        #region 属性
        private System.Web.UI.WebControls.WebControl _control;
        private int _min = int.MinValue;
        private int _max = int.MinValue;
        private int _minLength = int.MinValue;
        private int _maxLength = int.MinValue;
        private string _params;
        private View _view;

        public string Name { get; set; }
        public bool Enable { get; set; }
        public List<Validation> Validations { get; set; }
        public string Message { get; set; }
        public string Value { get; set; }
        public string SaveFolder { get; set; }
        public string Type { get; set; }
        #endregion

        #region 构造函数
        public MyField()
        {
            this.Validations = new List<Validation>();
        }
        public MyField(string name, View view)
            : this()
        {
            this.Name = name;
            _view = view;
        }
        #endregion

        #region 字段
        #region Text
        /// <summary>
        /// 文本字段
        /// </summary>
        /// <param name="size">文本宽度</param>
        /// <param name="value">默认文本</param>
        /// <param name="css">文本样式名称</param>
        /// <param name="mode">文本模式:单行、多行和密码框</param>
        /// <returns></returns>
        public MyField Text(int size = 100, string value = null, string css = null, TextBoxMode mode = TextBoxMode.SingleLine)
        {
            TextBox text = new TextBox();
            text.TextMode = mode;
            text.Width = size;
            text.Text = value;
            text.CssClass = css;
            _control = text as WebControl;
            return this;
        }
        /// <summary>
        /// 限制文本
        /// </summary>
        /// <param name="minLength">最小长度</param>
        /// <param name="size">宽度</param>
        /// <param name="maxLength">最大长度</param>
        /// <param name="value">值</param>
        /// <param name="css">样式</param>
        /// <returns></returns>
        public MyField TextLimit(int minLength, int size = 100, int maxLength = int.MinValue, string value = null, string css = null)
        {
            _minLength = minLength;
            _maxLength = maxLength;
            return Text(size, value, css);
        }
        #endregion
        #region TextArea文本域
        /// <summary>
        /// TextArea文本域
        /// </summary>
        /// <param name="height">高度</param>
        /// <param name="size">宽度</param>
        /// <param name="value">值</param>
        /// <param name="css">样式</param>
        /// <returns></returns>
        public MyField TextArea(int height, int size = 100, string value = null, string css = null)
        {
            TextBox text = new TextBox();
            text.Height = height;
            return Text(size, value, css);
        }
        #endregion
        #region Email
        /// <summary>
        /// 只能输入Email的文本框
        /// </summary>
        /// <param name="size">文本宽度</param>
        /// <param name="value">默认值</param>
        /// <param name="css">样式名称</param>
        /// <returns></returns>
        public MyField Email(int size = 100, string value = null, string css = null)
        {
            Validation(Mvc.Validation.email);
            return Text(size, value, css);
        }
        #endregion
        #region Number
        /// <summary>
        /// 数字控件
        /// </summary>
        /// <param name="size">输入框宽度</param>
        /// <param name="value">默认值</param>
        /// <param name="css">样式名称</param>
        /// <param name="min">最小值</param>
        /// <param name="max">最大值</param>
        /// <returns></returns>
        public MyField Number(int size, decimal value = 0, string css = null, int min = int.MinValue, int max = int.MinValue)
        {
            Validation(Mvc.Validation.number);
            _min = min;
            _max = max;
            return Text(size, value.ToString(), css);
        }
        #endregion
        #region CheckBox

        /// <summary>
        /// CheckBox
        /// </summary>
        /// <param name="label">复选框名称</param>
        /// <param name="isChecked">是否选中</param>
        /// <param name="css">样式名称</param>
        /// <returns>MyField</returns>
        public MyField CheckBox(string label, bool isChecked = false, string css = null)
        {
            CheckBox checkBox = new CheckBox();
            checkBox.Text = label;
            checkBox.Checked = isChecked;
            checkBox.CssClass = css;
            _control = checkBox;
            return this;
        }
        #endregion
        #region Radio

        /// <summary>
        /// Radio
        /// </summary>
        /// <param name="label">单选框名称</param>
        /// <param name="GroupName">组名</param>
        /// <param name="Checked">是否选中</param>
        /// <param name="css">样式名称</param>
        /// <returns>MyField</returns>
        public MyField Radio(string label, string GroupName, bool Checked = false, string css = null)
        {
            RadioButton radio = new RadioButton();
            radio.CssClass = css;
            radio.GroupName = GroupName;
            radio.Text = label;
            radio.Checked = Checked;
            _control = radio;
            return this;
        }
        #endregion
        #region 编辑器-Editor
        /// <summary>
        /// 编辑器
        /// </summary>
        /// <returns>返回MyField对象</returns>
        public MyField Editor()
        {
            _view.RegisterStartupJavascript("editorName", string.Format("editorName='{0}';", this.Name));
            _view.RegisterJavascriptInclude("ckeditor", true, "/ckeditor/ckeditor.js");
            _view.RegisterJavascriptInclude("editor_config", true, "/ckeditor/editor_config.js");
            TextBox text = new TextBox();
            text.TextMode = TextBoxMode.MultiLine;
            text.CssClass = "editor";
            _control = text;
            this.Type = "Editor";
            return this;
        }
        /// <summary>
        /// 小型编辑器
        /// </summary>
        /// <param name="width">宽</param>
        /// <param name="height">高</param>
        /// <returns>返回MyField对象</returns>
        public MyField SmallEditor(int width = 400, int height = 50)
        {
            _view.RegisterJavascriptInclude("smallEditor", true, "/content/scripts/nicEdit.js");
            _view.RegisterStartupJavascript("smallEditorLoad", string.Format("loadEditor('{0}');", this.Name));
            TextBox text = new TextBox();
            text.TextMode = TextBoxMode.MultiLine;
            text.Width = width;
            text.Height = height;
            _control = text;
            this.Type = "SmallEditor";
            return this;
        }
        #endregion
        #region 日期控件
        /// <summary>
        /// 日期控件
        /// </summary>
        /// <param name="dateTime">默认日期</param>
        /// <param name="disabled">是否禁用</param>
        /// <param name="CurrentMonth">是否从当前月一号开始</param>
        /// <param name="Width">长度</param>
        /// <returns>返回MyField对象</returns>
        public MyField Date(DateTime dateTime, Boolean disabled = false, Boolean CurrentMonth = false, int Width = 90)
        {
            string time = string.Empty;
            TextBox Date = new TextBox();
            if (!CurrentMonth)
            {
                time = dateTime.ToString("yyyy-MM-dd");
            }
            else
            {
                time = dateTime.ToString("yyyy-MM") + "-01";
            }
            Date.Attributes.Add("value", time);
            Date.Attributes.Add("disabled", disabled.ToString());
            Date.Width = Width;
            Date.CssClass = "easyui-datebox";
            _control = Date;
            //_view.RegisterCSSInclude("JQueryUIStyle", "/Content/css/ui/jquery.ui.css");
            //_view.RegisterJavascriptInclude("JQueryUI", true, "/Content/Scripts/jquery.ui.js");
            //_view.RegisterStartupJavascript(string.Format("Date{0}", this.Name), string.Format("$(function () {{setDate('{0}');}})", this.Name));
            return this;
        }
        #endregion
        #region DropDownList控件
        /// <summary>
        /// DropDownList控件
        /// </summary>
        /// <param name="dataSource">数据源</param>
        /// <param name="css">可选样式</param>
        /// <returns>返回MyField对象</returns>
        public MyField DropDownList(object dataSource, string dataTextField = "Name", string dataValueField = "ID", string selectText = null, string css = null)
        {
            DropDownList ddl = new DropDownList();
            ddl.DataTextField = dataTextField;
            ddl.DataValueField = dataValueField;
            ddl.CssClass = css;

            ddl.DataSource = dataSource;
            ddl.DataBind();
            if (selectText != null)
            {
                ddl.Items.Insert(0, new ListItem(selectText, ""));
            }
            _control = ddl;
            return this;
        }
        #endregion

        #region ComBoTree
        /// <summary>
        /// 树型下拉框
        /// </summary>
        /// <param name="url">数据加载地址</param>
        /// <param name="width">宽度</param>
        /// <param name="height">高度</param>
        /// <param name="css">样式名称</param>
        /// <returns>返回MyField对象</returns>
        public MyField ComBoTree(string url, int width = 500, int height = 200, string css = "easyui-combotree")
        {
            DropDownList ddl = new DropDownList();
            ddl.Attributes.Add("url", url);
            ddl.Width = width;
            ddl.Attributes.Add("cascadeCheck", "true");
            ddl.Attributes.Add("multiple", "true");
            ddl.Attributes.Add("panelHeight", height.ToString());
            ddl.CssClass = css;
            _control = ddl;
            return this;
        }
        #endregion

        #region 文件上传
        /// <summary>
        /// 上传控件
        /// </summary>
        /// <param name="saveFoler">保存的文件夹</param>
        /// <param name="width">浏览框宽度</param>
        /// <param name="css">样式名称</param>
        /// <returns>返回MyField对象</returns>
        public MyField File(string saveFoler = "uploadFiles", int width = 500, string css = null)
        {
            FileUpload fileUp = new FileUpload();
            fileUp.Width = width;
            fileUp.CssClass = css;
            fileUp.Attributes.Add("Text", "ss");
            _control = fileUp;
            SaveFolder = saveFoler;
            return this;
        }
        #endregion

        #region  日期查询
        /// <summary>
        /// 日期查询
        /// </summary>
        /// <param name="StartDate">起始日期</param>
        /// <param name="EndDate">结束日期</param>
        /// <param name="StartID">起始日期ID</param>
        /// <param name="EndID">结束日期ID</param>
        /// <param name="ToStr">链接符号</param>
        /// <returns></returns>
        public MyField DateQuery(DateTime StartDate, DateTime EndDate, string StartID = "StartDateID", String EndID = "EndDateID", string ToStr = "至")
        {
            WebControl control = new WebControl(System.Web.UI.HtmlTextWriterTag.Div);
            Literal DateText = new Literal();
            string StartDateStr = string.Format("value='{0}'", StartDate.ToString("yyyy-MM-dd"));
            string EndDateStr = string.Format("value='{0}'", EndDate.ToString("yyyy-MM-dd"));
            DateText.Text = string.Format("<input id='{0}' class='easyui-datebox' {3}></input>{2}<input id='{1}' class='easyui-datebox' {4}></input>", StartID, EndID, ToStr, StartDateStr, EndDateStr);
            control.Controls.Add(DateText);
            _control = control;
            return this;
        }
        #endregion



        #region 级别、等级
        /// <summary>
        /// 级别、等级
        /// </summary>
        /// <param name="max">最大等级数</param>
        /// <param name="messages">每个级别对应的提示</param>
        /// <returns>返回MyField对象</returns>
        public MyField Level(int max = 5, params string[] messages)
        {
            _view.RegisterJavascriptInclude("raty", true, "/content/scripts/raty/jquery.raty.min.js");
            WebControl control = new WebControl(System.Web.UI.HtmlTextWriterTag.Div);
            Literal levelText = new Literal();
            levelText.Text = string.Format("<input type=hidden name=\"{0}\" id=\"{0}\" value=\"#value\" />", this.Name);
            control.Controls.Add(levelText);
            this.Type = "Level";
            _max = max;
            _control = control;
            List<string> msgList = new List<string>();
            if (messages.Length > 0)
            {
                foreach (string msg in messages) msgList.Add(msg);
            }
            else
            {
                for (int i = 0; i < max; i++)
                {
                    msgList.Add(string.Format("级别{0}", i + 1));
                }
            }
            _params = "['" + string.Join("','", msgList.ToArray()) + "']";
            return this;
        }
        #endregion

        #endregion

        #region 公共方法
        #region 验证
        /// <summary>
        /// 表单验证方法
        /// </summary>
        /// <param name="validation"></param>
        public void Validation(params Validation[] validation)
        {
            this.Validations.AddRange(validation);
        }
        #endregion
        #region 添加属性
        public MyField AddAttr(string name, string value)
        {
            _control.Attributes.Add(name, value);
            return this;
        }
        #endregion
        #region 输出HTML
        public string Render(object value = null)
        {
            _control.ID = this.Name;
            #region 设置Value
            if (!string.IsNullOrEmpty(string.Format("{0}", value))) this.Value = string.Format("{0}", value);
            if (_control is TextBox)
            {
                TextBox textBox = _control as TextBox;
                //if (!string.IsNullOrEmpty(_minLength.ToString()))
                //{

                //}
                if (!string.IsNullOrEmpty(string.Format("{0}", value)))
                    textBox.Text = string.Format("{0}", value);
            }
            else if (_control is RadioButton)
            {
                _control.Attributes.Add("Value", this.Value);
            }
            else if (_control is CheckBox)
            {
                CheckBox check = _control as CheckBox;
                //  check.Checked = this.Value == "True" ? true : false;
            }
            else if (_control is DropDownList)
            {
                DropDownList downList = _control as DropDownList;
                foreach (ListItem item in downList.Items)
                {
                    if (item.Value == this.Value)
                    {
                        item.Selected = true;
                        break;
                    }
                }
            }

            #endregion
            StringBuilder css = new StringBuilder();
            css.AppendFormat("{0}", _control.CssClass);
            if (this.Validations.Count > 0)
            {
                css.Append(" {");
                foreach (Vici.Mvc.Validation validation in this.Validations)
                {
                    css.AppendFormat(" {0}:true,", validation);
                }
                if (css.ToString().EndsWith(",")) css.Remove(css.Length - 1, 1);
                if (_minLength != int.MinValue)
                {
                    css.AppendFormat(",minlength:{0}", _minLength);
                }
                if (_maxLength != int.MinValue)
                {
                    css.AppendFormat(",maxlength:{0}", _maxLength);
                }
                css.Append("}");
            }
            if (this.Type == "Level")
            {
                _control.ID = string.Format("{0}Raty", this.Name);
                css.Insert(0, "level ");
            }
            _control.CssClass = css.ToString();
            string result = string.Empty;
            using (System.IO.StringWriter sw = new System.IO.StringWriter())
            {
                using (System.Web.UI.HtmlTextWriter htmlW = new System.Web.UI.HtmlTextWriter(sw))
                {
                    _control.RenderControl(htmlW);
                }
                result = sw.ToString();
            }
            switch (this.Type)
            {
                case "Editor":
                    result += string.Format("<input type=hidden name=\"{0}_Editor\" id=\"{0}_Editor\" />", this.Name);
                    break;
                case "Level":
                    if (string.IsNullOrEmpty(this.Value)) this.Value = "0";
                    result = result.Replace("#value", this.Value);
                    this._view.RegisterStartupJavascript(this.Name, string.Format("$('#{1}').raty({{start:{2}, number:{0}, path: '/content/scripts/raty/img', hintList: {3}, onClick: function(score) {{$('#{4}').attr('value',score);}} }})", _max, _control.ID, this.Value, _params, this.Name));
                    break;
            }
            return result;
        }
        #endregion
        #endregion
    }
}
